package com.frank.loadinglibrary.common.element;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import com.frank.loadinglibrary.utils.interpolator.FastOutSlowInInterpolator;
import com.frank.timber.Timber;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;

import java.util.ArrayList;

public class WhorArcLoadingElement extends BaseElement implements BaseAnimationController.IAnimationController<AnimatorValue> {
    private static final int DEGREE_180 = 180;
    private static final int DEGREE_360 = 360;
    //起点绘制结束时进度
    private static final float START_TRIM_DURATION_OFFSET = 0.5f;
    //单次绘制画弧所占角度
    private static final float MAX_SWIPE_DEGREES = 0.6f * DEGREE_360;
    //整个绘制区域对应的矩形
    private RectFloat mTempBounds;
    //圆弧对应矩形区域
    private final RectFloat mTempArcBounds = new RectFloat();
    //画布旋转角度
    private float mCanvasRotation;
    //插值器 先快后慢再快
    private FastOutSlowInInterpolator interpolator = new FastOutSlowInInterpolator();
    //上一次的终点点角度
    private float mOriginEndDegrees = 0;
    //上一次的起点角度
    private float mOriginStartDegrees = 0;
    //终点角度
    private float mEndDegrees;
    //记录当前旋转的角度
    private float mOriginRotateDegrees = 0;
    //记录起点角度
    private float mStartDegrees;
    //记录绘制的圆弧角度
    private float mSwipeDegrees;
    private Paint mPaint;

    private WhorArcLoadingParams params;

    public WhorArcLoadingElement(WhorArcLoadingParams params, IComponentCallback call) {
        super();
        this.params = params;
        this.callback = call;
    }


    @Override
    public void initPaint() {
        super.initPaint();
        if (mPaint == null) {
            mPaint = new Paint();
        }
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(params.mStrokeWidth);
        mPaint.setStyle(Paint.Style.STROKE_STYLE);
        mPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        int savecount = canvas.save();
        if (mTempBounds == null) {
            mTempBounds = new RectFloat();
            float width = Math.min(getWidth(), getHeight());
            mTempBounds.modify((getWidth() - width) / 2 + params.mMaginInset, (getHeight() - width) / 2 + params.mMaginInset, (getWidth() - width) / 2 - params.mMaginInset + width, (getHeight() - width) / 2 + width - params.mMaginInset);
        }
        canvas.rotate(mCanvasRotation, getWidth() / 2, getHeight() / 2);

        if (mSwipeDegrees != 0) {
            for (int i = 0; i < params.mColors.length; i++) {
                mPaint.setStrokeWidth(params.mStrokeWidth / (i + 1));
                mPaint.setColor(params.mColors[i]);
                canvas.drawArc(createArcBounds(mTempBounds, i), new Arc(mStartDegrees + DEGREE_180 * (i % 2),
                        mSwipeDegrees, false), mPaint);
            }
        }
        canvas.restoreToCount(savecount);
    }

    @Override
    public ArrayList<AnimatorValue> onCreateAnimators() {
        ArrayList<AnimatorValue> list = new ArrayList<>();
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setLoopedCount(-1);
        animatorValue.setDuration(params.durtion);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            computeDrawParams(v);
            if (callback != null) {
                callback.reflushComponent();
            }
        });
        animatorValue.setLoopedListener(animator -> {
            resetOriginals();
            mStartDegrees = mEndDegrees;
            mOriginRotateDegrees = mCanvasRotation;
        });
        list.add(animatorValue);
        return list;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset Animation params
    }

    @Override
    public BaseAnimationController.IAnimationController initAnimationController() {
        return this;
    }

    private RectFloat createArcBounds(RectFloat sourceArcBounds, int index) {
        int intervalWidth = 0;

        for (int i = 0; i < index; i++) {
            intervalWidth += params.mStrokeWidth / (i + 1.0f) * 1.5f;
        }

        int arcBoundsLeft = (int) (sourceArcBounds.left + intervalWidth);
        int arcBoundsTop = (int) (sourceArcBounds.top + intervalWidth);
        int arcBoundsRight = (int) (sourceArcBounds.right - intervalWidth);
        int arcBoundsBottom = (int) (sourceArcBounds.bottom - intervalWidth);
        mTempArcBounds.modify(arcBoundsLeft, arcBoundsTop, arcBoundsRight, arcBoundsBottom);

        return mTempArcBounds;
    }

    private void computeDrawParams(float value) {
        if (value <= START_TRIM_DURATION_OFFSET) {

            float startTrimProgress = value / (1.0f - value);

            mStartDegrees = mOriginStartDegrees + MAX_SWIPE_DEGREES * interpolator.getInterpolation(startTrimProgress);
        }
        if (value > START_TRIM_DURATION_OFFSET) {
            float endTrimProgress = (value - START_TRIM_DURATION_OFFSET) / START_TRIM_DURATION_OFFSET;
            mEndDegrees = mOriginEndDegrees + MAX_SWIPE_DEGREES * interpolator.getInterpolation(endTrimProgress);
        }
        if (Math.abs(mEndDegrees - mStartDegrees) > 0) {
            mSwipeDegrees = mEndDegrees - mStartDegrees;
        }
        mCanvasRotation = (mOriginRotateDegrees + 216 * value) % 360;
    }

    private void resetOriginals() {
        mOriginEndDegrees = 0;
        mOriginStartDegrees = 0;

        mEndDegrees = 0;
        mStartDegrees = 0;

        mSwipeDegrees = 0;
    }


    /**
     * 构建者
     */
    public static class WhorArcLoadingBuilder {
        WhorArcLoadingParams params;
        IComponentCallback call;
        private static final int VALUETHREE = 3;

        public WhorArcLoadingBuilder(IComponentCallback c) {
            call = c;
            params = new WhorArcLoadingParams();
            setDurtion(WhorArcLoadingParams.BASE_DURTION_TIME);
        }

        public WhorArcLoadingBuilder setDurtion(int dur) {
            params.durtion = dur;
            return this;
        }

        public WhorArcLoadingBuilder setColor(String[] color) {
            if (color != null && color.length == VALUETHREE) {
                //只有3段圆弧
                for (int i = 0; i < color.length; i++) {
                    params.mColors[i] = new Color(Color.getIntColor(color[i]));
                }
            } else {
                Timber.d("color size is not 3");
            }
            return this;
        }

        public WhorArcLoadingBuilder setStrokeWidth(int stw) {
            params.mStrokeWidth = stw;
            return this;
        }

        public WhorArcLoadingElement build() {
            return new WhorArcLoadingElement(params, call);
        }
    }


    public static class WhorArcLoadingParams {
        //记录三条轨迹的颜色值数组
        private static final Color[] DEFAULT_COLORS = new Color[]{
                Color.RED, Color.GREEN, Color.BLUE
        };
        private static final int BASE_DURTION_TIME = 2000;
        private int durtion = BASE_DURTION_TIME;
        private Color[] mColors = DEFAULT_COLORS;
        //最外层圆弧的画笔宽度
        private float mStrokeWidth = 15;
        //最外层圆弧 对应矩形 与边界的边距
        private float mMaginInset = 20;
    }
}
